using System;
using Microsoft.SharePoint;

namespace SharePoint.DataMapper
{
	[FieldMapper(typeof(SPField), SPFieldType.Invalid)]
	[FieldMapper(typeof(SPFieldBoolean), SPFieldType.Boolean)]
	[FieldMapper(typeof(SPFieldAllDayEvent), SPFieldType.AllDayEvent)]
	[FieldMapper(typeof(SPFieldRecurrence), SPFieldType.Recurrence)]
	[FieldMapper(typeof(SPFieldCrossProjectLink), SPFieldType.CrossProjectLink)]
	public class FieldMapper : IFieldMapper
	{
		protected virtual SPField AddFieldInternal(ListDataContext context, SPFieldCollection collection, Type propertyType, FieldAttribute attribute)
		{
			string name = collection.Add(attribute.Field, attribute.FieldType, attribute.Required);
			SPField field =  collection.GetFieldByInternalName(name);
			SetFieldPropertiesInternal(field, attribute);
			return field;
		}

		protected virtual void SetFieldPropertiesInternal(SPField field, FieldAttribute attribute)
		{
			if (!string.IsNullOrEmpty(attribute.DisplayName))
			{
				field.Title = attribute.DisplayName;
			}
			field.Hidden = attribute.Hidden;
			field.Description = attribute.Description;
			field.DefaultValue = attribute.DefaultValue;
			field.ShowInDisplayForm = true;
			field.ShowInEditForm = true;
			field.ShowInNewForm = true;
			field.ShowInListSettings = true;
			field.ShowInVersionHistory = true;
			field.ShowInViewForms = true;
		}

		protected virtual FieldAttribute GetFieldAttributeInternal(SPField field)
		{
			FieldAttribute attribute = new FieldAttribute(field.InternalName, field.Type)
			{
				Description = field.Description,
				DisplayName = field.Title,
				DefaultValue = field.DefaultValue,
				//Additional = !field.FromBaseType,
				Required = field.Required,
				ReadOnly = field.ReadOnlyField,
				Hidden = field.Hidden
			};
			if (field.Type == SPFieldType.Invalid)
			{
				attribute.Type = field.GetType();
			}
			return attribute;
		}

		protected virtual object SetFieldInternal(ListDataContext context, object value, Type propertyType)
		{
			return value;
		}

		protected virtual object GetFieldInternal(ListDataContext context, object value, Type propertyType)
		{
			return value;
		}

		#region IFieldMapper Members

		public SPField AddField(ListDataContext context, SPFieldCollection collection, Type propertyType, FieldAttribute attribute)
		{
			SPField field = AddFieldInternal(context, collection, propertyType, attribute);
			field.Update();
			return field;
		}

		public FieldAttribute GetFieldAttribute(SPField field)
		{
			if (field == null)
				throw new ArgumentNullException("field");

			return GetFieldAttributeInternal(field);
		}

		public object SetField(ListDataContext context, object value, Type propertyType)
		{
			if (value == null)
				return null;

			if (context == null)
				throw new ArgumentNullException("context");

			if (propertyType == null)
				throw new ArgumentNullException("propertyType");

			return SetFieldInternal(context, value, propertyType);
		}

		public object GetField(ListDataContext context, object value, Type propertyType)
		{
			if (value == null)
				return null;

			if (context == null)
				throw new ArgumentNullException("context");

			if (propertyType == null)
				throw new ArgumentNullException("propertyType");

			if (propertyType == typeof(string))
                return value.ToString();

			return GetFieldInternal(context, value, propertyType);
		}

		#endregion
	}
}